<?php

namespace App\Modules\Payment\Models;

use App\Exceptions\StandardException;
use App\Modules\User\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Overtrue\LaravelWeChat\Facade as EasyWeChat;
use Ramsey\Uuid\Uuid;

/**
 * Class WeChatPay
 *
 * @property int $id
 * @property int $user_id
 * @property string $type
 * @property string $appid
 * @property string $mch_id
 * @property string $device_info
 * @property string $nonce_str
 * @property string $sign
 * @property string $sign_type
 * @property string $body
 * @property string $detail
 * @property string $attach
 * @property string $out_trade_no
 * @property string $fee_type
 * @property integer $total_fee
 * @property string $spbill_create_ip
 * @property string $time_start
 * @property string $time_expire
 * @property string $trade_type
 * @property string $openid
 * @property string $prepay_id
 * @property boolean $notified
 * @property boolean $transaction_id
 * @property string $result_code
 * @property string $err_code
 * @property string $err_code_des
 * @property string $is_subscribe
 * @property string $bank_type
 * @property string $time_end
 * @property integer $refund_fee
 * @package App\Modules\Order\Models
 */
class WeChatPay extends Model
{
    protected $fillable = [
        "user_id",
        "type",
        "appid",
        "mch_id",
        "device_info",
        "nonce_str",
        "sign",
        "sign_type",
        "body",
        "detail",
        "attach",
        "out_trade_no",
        "fee_type",
        "total_fee",
        "spbill_create_ip",
        "time_start",
        "time_expire",
        "trade_type",
        "openid",
        "prepay_id",
        "notified",
        "transaction_id",
        "result_code",
        "err_code",
        "err_code_des",
        "is_subscribe",
        "bank_type",
        "time_end",
        "refund_fee"
    ];

    /**
     * Get parameters for jssdk
     * @param string $type
     * @param string $outTradeNo
     * @param string $name
     * @param int $price
     * @param User $user
     * @return array
     * @throws StandardException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function getParameters(string $type, string $outTradeNo, string $name, int $price, User $user, $isH5 = 0)
    {
        if ($isH5) {
            $openid = $user->official_account_openid;
            $payment = EasyWeChat::payment('official_account');
        } else {
            $openid = $user->openid;
            $payment = EasyWeChat::payment();
        }

        $result = $payment->order->unify([
            'trade_type' => 'JSAPI',
            'body' => mb_substr(self::filterEmoji($name), 0, 15),
            'out_trade_no' => $outTradeNo,
            'total_fee' => $price,
            'openid' => $openid,
        ]);
        if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
            static::create([
                'type' => $type,
                "user_id" => $user->id,
                "body" => filterEmoji($name),
                "out_trade_no" => $outTradeNo,
                "total_fee" => $price,
                "trade_type" => 'JSAPI',
                "openid" => $user->openid,
                "prepay_id" => $result['prepay_id'],
                "appid" => $result['appid'],
                "mch_id" => $result['mch_id'],
                "nonce_str" => $result['nonce_str'],
                "sign" => $result['sign'],
                "result_code" => $result['result_code'],
            ]);
            return $payment->jssdk->sdkConfig($result['prepay_id']);
        } else {
            throw new StandardException("支付错误");
        }
    }

    public static function filterEmoji($str)
    {
        $str = preg_replace_callback('/./u',
            function (array $match) {
                return strlen($match[0]) >= 4 ? '' : $match[0];
            },
            $str);
        return $str;
    }

    /**
     * @param array $data
     */
    public function notify(array $data)
    {
        $this->fill(Arr::only($data, [
            "transaction_id", "result_code", "err_code", "err_code_des", "is_subscribe", "bank_type", "fee_type", "time_end"
        ]));
        $this->notified = true;
        $this->save();

        if ($data['return_code'] == 'SUCCESS' && $data['result_code'] == 'SUCCESS') {

            $isSendMsg = false;// 是否发送模板消息，支付成功后更新为true

            try {
                $order = ($this->type)::query()->where('pay_no', $this->out_trade_no)->first();
                if($order->status == "paid"){
                    return sprintf("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
                }
                $order->active($this->total_fee);

                $isSendMsg = true;
                // 支付失败时要在return_msg里边告诉他们支付失败的原因，这个原因微信会在回调的时候已xml的格式告诉你。字段为return_msg
                // $this->sendMessage($order);
            } catch (\Throwable $e) {
                $order = ($this->type)::query()->where('pay_no', $this->out_trade_no)->first();
                /** @var WeChatRefund $refund */
                $weChatRefund = WeChatRefund::query()->create([
                    'order_type' => $this->type,
                    "order_id" => $order->id,
                    'out_trade_no' => $this->out_trade_no,
                    'transaction_id' => $this->transaction_id,
                    'out_refund_no' => Uuid::uuid4()->getInteger(),
                    'total_fee' => $this->total_fee,
                    'refund_fee' => $this->total_fee,
                    'refund_desc' => '订单支付失败',
                    'refund_account' => config('wechat.payment.refund_account', 'REFUND_SOURCE_UNSETTLED_FUNDS'),
                    'status' => WeChatRefund::STATUS_INITIALIZED
                ]);
                $weChatRefund->execute();
            }

            // 如果订单支付成功 走发送模板消息的方法 -by 21.09.30
            if ($isSendMsg) {
                $this->sendMessage($order);
            }

            return sprintf("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");

        }
    }

    public function sendMessage($order)
    {
        //支付成的通知、推荐下单成功的通知、城市合伙人推荐别人下单的通知
        /**
         *  临洮：支付成功通知->这段在服务器测试
         *  模板ID：7MQKNeFhrqdE9G3K6NyOsYKnVYuXzpPsIj1vmm7PAck
         *  格式：
         * {{first.DATA}}
         * 商品名称：{{keyword1.DATA}}
         * 订单编号：{{keyword2.DATA}}
         * 支付金额：{{keyword3.DATA}}
         * {{remark.DATA}}
         */

        $user = User::query()
            ->whereRaw("JSON_CONTAINS(shop_id, '\"" . $order->shop_id . "\"')")
            ->where("is_palm_management", 1)
            ->get(["openid", "is_palm_management"])->toArray();
        Log::channel('pay')->info('商家的用户信息', $user);
        $sendData = [$this->openid, $order->title, $order->id, ($order->price / 100) . "元"];
        if ($order->delivery == 0 && $order->is_prepay == 1) { //到店自取-定金支付
            sendMessage(8, $sendData);
            sendSystem($user, 40, $sendData);
        } elseif ($order->delivery == 0 && $order->is_prepay == 0) {//到店自取-全款支付
            sendMessage(9, $sendData);
            sendSystem($user, 41, $sendData);
        } elseif ($order->delivery > 0 && $order->is_prepay == 1) {//物流发货-定金支付
            sendMessage(10, $sendData);
            sendSystem($user, 42, $sendData);
        } elseif ($order->delivery > 0 && $order->is_prepay == 0) {//物流发货-全款支付
            sendMessage(11, $sendData);
            sendSystem($user, 43, $sendData);
        }
        Log::channel('pay')->info('支付成功通知', $sendData);

        /**
         * 临洮： 推荐下单成功
         * 您好，【金程圆】已通过扫描您的专属二维码被推荐成为会员。
         *{{first.DATA}}
         * 会员姓名：{{keyword1.DATA}}
         * 推荐人：{{keyword2.DATA}}
         * 时间：{{keyword3.DATA}}
         * {{remark.DATA}}
         */
        if ($order->referrer_id != $order->user_id && $order->referrer_id != null) {
            $template = DB::table("templates")->find(32);
            $user = User::query()->find($order->user_id);
            $referrer = User::query()->find($order->referrer_id);
            if ($referrer) {  //如果介绍人存在
                $first = vsprintf(json_decode($template->json, true)['first'], array($user->name));
                $sendData = [
                    0 => $referrer->openid,
                    1 => $user->name,
                    2 => $referrer->name,
                    3 => date("Y年m月d日 H时i分s秒"),
                    "first" => $first
                ];
                sendMessage(32, $sendData);
                Log::channel('pay')->info('推荐下单成功1', $sendData);
            }

            /**
             * 商家职员的下级城市合伙人推荐别人下单成功后的提醒——城市合伙人推荐别人
             * 成功下单后，给上级商家职员的提醒【提醒范围：此城市合伙人关联的上级商家 职员】
             */
            if ($referrer->personal_id) {
                $personal = User::query()->find($referrer->personal_id);
                if ($personal) {
                    $template = DB::table("templates")->find(33);
                    $first = vsprintf(json_decode($template->json, true)['first'], array($referrer->name, $user->name));
                    $sendData = [
                        0 => $personal->openid,
                        1 => $user->name,
                        2 => $referrer->name,
                        3 => date("Y年m月d日 H时i分s秒"),
                        "first" => $first
                    ];
                    sendMessage(32, $sendData);
                    Log::channel('pay')->info('推荐下单成功2', $sendData);
//                    uniformMessage($sendData);
                }
            }


        }

    }

}
